library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ---------------------------------
filter(): dplyr, stats
lag():    dplyr, stats

12.2 Tidy data

12.2.1 Exercises

  1. Using prose, describe how the variables and observations are organised in each of the sample tables.

table2: The type column indicates whether each row of data contains an observation of the number of cases or the population. This then means that the values for country and year are duplicated across two rows - each observation is split across those two rows.

table3: The rate column in this case is a string that contains two separate values - cases and population. Attempting to perform any computation or aggregation with the data in this format would need this string to be broken into separate numeric variables first.

table4: There are two separate tables, one for the cases variable and the other for population. Within each table the rows correspond to a country and the columns then contain separate observations on the target variable for each given year. This means that there are multiple observations within each row, yet the observations within each table are incomplete.

  1. Compute the rate for table2, and table4a + table4b. You will need to perform four operations:

  2. Extract the number of TB cases per country per year.
  3. Extract the matching population per country per year.
  4. Divide cases by population, and multiply by 10000.
  5. Store back in the appropriate place.

t2cases <- table2 %>%
  filter(type == "cases") %>%
  select(country, year, cases = count)
t2pop <- table2 %>%
  filter(type == "population") %>%
  select(country, year, pop = count)
t2rate <- t2cases %>%
  left_join(t2pop, by = c("country", "year")) %>%
  mutate(rate = (cases / pop) * 10000)
t2rate
t4rate <- table4a %>%
  left_join(table4b, by = c("country"), suffix = c("cases", "pop")) %>%
  mutate(
    `1999rate` = (`1999cases` / `1999pop`) * 10000,
    `2000rate` = (`2000cases` / `2000pop`) * 10000
  )
t4rate

Which representation is easiest to work with? Which is hardest? Why?

table3 would be worst of all because it requires text processing. table2 required some intermediate steps before putting things back together but results in a generally tidy format. table4a and table4b required some extra arguments to the join function for clarity and ends up putting the calculated rates into two separate columns so it remains untidy.

  1. Recreate the plot showing change in cases over time using table2 instead of table1. What do you need to do first?
library(ggplot2)
table2 %>%
  filter(type == "cases") %>%
  ggplot(aes(year, count)) +
    geom_line(aes(group = country), colour = "grey50") +
    geom_point(aes(colour = country)) +
    ylab("cases")

I needed to filter the data to select only the rows that had numbers of cases, and then I also changed the label on the y-axis to correctly describe the variable.

12.3 Spreading and gathering

12.3.3 Exercises

  1. Why are gather() and spread() not perfectly symmetrical?

Carefully consider the following example:

stocks <- tibble(
  year   = c(2015, 2015, 2016, 2016),
  half  = c(   1,    2,     1,    2),
  return = c(1.88, 0.59, 0.92, 0.17)
)
stocks %>% 
  spread(year, return)  %>% 
  gather("year", "return", `2015`:`2016`)

(Hint: look at the variable types and think about column names.)

spread() only needs two arguments because it determines the new column names from the values in the key column. All it needs to do is coerce those values to be strings so they can function as variable names. gather() needs to be told the new column names and then which existing variables are to be converted into those key-value columns.

Both spread() and gather() have a convert argument. What does it do?

If convert = TRUE is passed to either function then it will attempt to convert the new variables to an appropriate type. Note that year in the example code above has ended up as a string, because the gather() function had used the 2015 and 2016 variable names as strings. Running the same code with conversion will see it return to being a numeric variable, as shown below.

stocks <- tibble(
  year   = c(2015, 2015, 2016, 2016),
  half  = c(   1,    2,     1,    2),
  return = c(1.88, 0.59, 0.92, 0.17)
)
stocks %>% 
  spread(year, return)  %>% 
  gather("year", "return", `2015`:`2016`, convert = TRUE)
  1. Why does this code fail?
table4a %>% 
  gather(1999, 2000, key = "year", value = "cases")
Error: Position must be between 0 and n

The existing variable names are non-syntactic so the arguments need to be surrounded by backticks - see below.

table4a %>% 
  gather(`1999`, `2000`, key = "year", value = "cases")
  1. Why does spreading this tibble fail? How could you add a new column to fix the problem?
people <- tribble(
  ~name,             ~key,    ~value,
  #-----------------|--------|------
  "Phillip Woods",   "age",       45,
  "Phillip Woods",   "height",   186,
  "Phillip Woods",   "age",       50,
  "Jessica Cordero", "age",       37,
  "Jessica Cordero", "height",   156
)
people %>%
  spread(key, value)
Error: Duplicate identifiers for rows (1, 3)

The third row in the original dataset has the same name and key as the first row, i.e., the function runs into a situation where there are two possible values to go into the one cell for Phillip Woods’s age column. You could add a column that allows the tidying function to uniquely identify people who might have the same name, e.g., add an address or a unique ID number.

  1. Tidy the simple tibble below. Do you need to spread or gather it? What are the variables?
preg <- tribble(
  ~pregnant, ~male, ~female,
  "yes",     NA,    10,
  "no",      20,    12
)
preg %>%
  gather("sex", "n", `male`:`female`)

12.4 Separating and uniting

12.4.3 Exercises

  1. What do the extra and fill arguments do in separate()? Experiment with the various options for the following two toy datasets.
?separate

These two arguments allow us to specify what happens with any row(s) that has too many (extra) or too few (fill) pieces to fit the into variables. By default, warnings will be issued in both cases, but we can instead drop extra values or merge them into the final column, and we can specify whether missing values should be filled on the right (final column(s)) or left.

tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>% 
  separate(x, c("one", "two", "three"))
Too many values at 1 locations: 2
tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>% 
  separate(x, c("one", "two", "three"), extra = "drop")
tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>% 
  separate(x, c("one", "two", "three"), extra = "merge")
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>% 
  separate(x, c("one", "two", "three"))
Too few values at 1 locations: 2
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>% 
  separate(x, c("one", "two", "three"), fill = "right")
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>% 
  separate(x, c("one", "two", "three"), fill = "left")
  1. Both unite() and separate() have a remove argument. What does it do? Why would you set it to FALSE?

It removes the input column(s) after you’ve separated or united your data. The default is TRUE but you would set it to FALSE if you wanted to retain the original data for any reason, whether that is in case you might need to re-run the function with adjustments or if the original data format is also useful for analysis in some way.

  1. Compare and contrast separate() and extract(). Why are there three variations of separation (by position, by separator, and with groups), but only one unite?
?tidyr::extract

extract() lets you specify regular expressions with capturing groups and would support more complex regular expressions to process the values - if the groups don’t match then the data will come out as NA. separate() is the more simple approach that likely works for most circumstances where you just need to specify a separator, and it also separates by position. There are three approaches to separation but only one for uniting because data that requires separation can come in any variety of forms and you need a method that works for the specific form your data comes in - it might have a separator, it might not have separators but have fixed positioning, etc. On the other hand, joining values together can be dealt with in a single method that provides the necessary parameters (e.g., separator, which can also be set to an empty string).

12.5 Missing values

12.5.1 Exercises

  1. Compare and contrast the fill arguments to spread() and complete().
?spread
?complete

The fill argument in spread() specifies what any missing values - both explicit and implicit - will be set to in the new columns. By default it will be NA but can be set to any other value. In complete(), the fill argument provides a named list that identifies for each variable whatvalue should be used when an implicit missing value is converted to explicit missing. The same value will also replace existing explicit missing values. Both approaches appear to ensure that implicit missing values become explicit, and they provide the possibility of using an alternative value instead of NA.

  1. What does the direction argument to fill() do?

By default it specifies that the fill should be down, ie the missing value should be filled by the nearest value above it, but it can also specify up instead.

12.6 Case Study

12.6.1 Exercises

  1. In this case study I set na.rm = TRUE just to make it easier to check that we had the correct values. Is this reasonable? Think about how missing values are represented in this dataset. Are there implicit missing values? What’s the difference between an NA and zero?
who %>%
  gather(code, value, new_sp_m014:newrel_f65) %>% 
  mutate(code = stringr::str_replace(code, "newrel", "new_rel")) %>%
  separate(code, c("new", "type", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1)
who %>%
  gather(code, value, new_sp_m014:newrel_f65) %>% 
  mutate(code = stringr::str_replace(code, "newrel", "new_rel")) %>%
  separate(code, c("new", "type", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1) %>%
  complete(country, year, type, sex, age)

The addition of more than 10,000 rows using complete() on the tidy dataset suggests that there were implicit missing values. An NA value indicates that we don’t know how many cases there were within the given combination of country, year, type, sex and age, whereas a zero indicates that there were no observed cases. Although it can be convenient and helpful when producing the data processing commands to strip out the missing values, analysis of the missing data can itself be informative, e.g., were records in some countries more likely to be incomplete?

  1. What happens if you neglect the mutate() step? (mutate(key = stringr::str_replace(key, "newrel", "new_rel")))
who %>%
  gather(code, value, new_sp_m014:newrel_f65) %>% 
  # mutate(code = stringr::str_replace(code, "newrel", "new_rel")) %>%
  separate(code, c("new", "type", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1)
Too few values at 101360 locations: 304081, 304082, 304083, 304084, 304085, 304086, 304087, 304088, 304089, 304090, 304091, 304092, 304093, 304094, 304095, 304096, 304097, 304098, 304099, 304100, ...

The rows that have a missing underscore in the key column (values beginning with newrel rather than new_rel) won’t separate properly as they will put newrel into the "new" variable, the value that should be sexage into the type column and will have nothing left to go into the sexage column.

  1. I claimed that iso2 and iso3 were redundant with country. Confirm this claim.
who %>%
  group_by(country, iso2, iso3) %>%
  summarise(count = n())

Inspection of the summarised data shows that each country has a single corresponding iso2 value and a single iso3 value.

  1. For each country, year, and sex compute the total number of cases of TB. Make an informative visualisation of the data.

A time-series line plot for each country with separate coloured lines for males and females would be informative about trends over time in each country as well as any sex differences. With more than 200 countries in the dataset a standard small multiples plot using a facet function won’t be readable, so we use the ggforce package’s paginated facet plotting capability. Because there is significant variation (orders of magitude) between countries in the number of cases a uniform scale across the facets’ y-axis would mean each individual subplot isn’t clearly visualised, so the scales = "free_y" argument is used. The pages are generated via a for loop - it takes a considerable time to run but produces plots that are generally clear and informative.

library(ggforce)
who2 <- who %>%
  gather(code, value, new_sp_m014:newrel_f65, na.rm = TRUE) %>% 
  mutate(code = stringr::str_replace(code, "newrel", "new_rel")) %>%
  separate(code, c("new", "type", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1) %>%
  group_by(country, year, sex) %>%
  summarise(cases = sum(value))
p <- who2 %>%
  ggplot(aes(x = year, y = cases, colour = sex)) +
    geom_line() +
    facet_wrap_paginate("country", ncol = 3, nrow = 3, scales = "free_y", page = 1)
pages <- n_pages(p)
for(i in 1:pages) {
  print(
    who2 %>%
      ggplot(aes(x = year, y = cases, colour = sex)) +
        geom_line() +
        facet_wrap_paginate("country", ncol = 3, nrow = 3, scales = "free_y", page = i)
  )
}

LS0tCnRpdGxlOiAiQ2hhcHRlciAxMjogVGlkeSBkYXRhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyAxMi4yIFRpZHkgZGF0YQoKIyMgMTIuMi4xIEV4ZXJjaXNlcwoKMS4gVXNpbmcgcHJvc2UsIGRlc2NyaWJlIGhvdyB0aGUgdmFyaWFibGVzIGFuZCBvYnNlcnZhdGlvbnMgYXJlIG9yZ2FuaXNlZCBpbiBlYWNoIG9mIHRoZSBzYW1wbGUgdGFibGVzLgoKKipgdGFibGUyYDogVGhlIGB0eXBlYCBjb2x1bW4gaW5kaWNhdGVzIHdoZXRoZXIgZWFjaCByb3cgb2YgZGF0YSBjb250YWlucyBhbiBvYnNlcnZhdGlvbiBvZiB0aGUgbnVtYmVyIG9mIGNhc2VzIG9yIHRoZSBwb3B1bGF0aW9uLiBUaGlzIHRoZW4gbWVhbnMgdGhhdCB0aGUgdmFsdWVzIGZvciBgY291bnRyeWAgYW5kIGB5ZWFyYCBhcmUgZHVwbGljYXRlZCBhY3Jvc3MgdHdvIHJvd3MgLSBlYWNoIG9ic2VydmF0aW9uIGlzIHNwbGl0IGFjcm9zcyB0aG9zZSB0d28gcm93cy4qKgoKKipgdGFibGUzYDogVGhlIGByYXRlYCBjb2x1bW4gaW4gdGhpcyBjYXNlIGlzIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgdHdvIHNlcGFyYXRlIHZhbHVlcyAtIGBjYXNlc2AgYW5kIGBwb3B1bGF0aW9uYC4gQXR0ZW1wdGluZyB0byBwZXJmb3JtIGFueSBjb21wdXRhdGlvbiBvciBhZ2dyZWdhdGlvbiB3aXRoIHRoZSBkYXRhIGluIHRoaXMgZm9ybWF0IHdvdWxkIG5lZWQgdGhpcyBzdHJpbmcgdG8gYmUgYnJva2VuIGludG8gc2VwYXJhdGUgbnVtZXJpYyB2YXJpYWJsZXMgZmlyc3QuKioKCioqYHRhYmxlNGA6IFRoZXJlIGFyZSB0d28gc2VwYXJhdGUgdGFibGVzLCBvbmUgZm9yIHRoZSBgY2FzZXNgIHZhcmlhYmxlIGFuZCB0aGUgb3RoZXIgZm9yIGBwb3B1bGF0aW9uYC4gV2l0aGluIGVhY2ggdGFibGUgdGhlIHJvd3MgY29ycmVzcG9uZCB0byBhIGNvdW50cnkgYW5kIHRoZSBjb2x1bW5zIHRoZW4gY29udGFpbiBzZXBhcmF0ZSBvYnNlcnZhdGlvbnMgb24gdGhlIHRhcmdldCB2YXJpYWJsZSBmb3IgZWFjaCBnaXZlbiB5ZWFyLiBUaGlzIG1lYW5zIHRoYXQgdGhlcmUgYXJlIG11bHRpcGxlIG9ic2VydmF0aW9ucyB3aXRoaW4gZWFjaCByb3csIHlldCB0aGUgb2JzZXJ2YXRpb25zIHdpdGhpbiBlYWNoIHRhYmxlIGFyZSBpbmNvbXBsZXRlLioqCgoyLiBDb21wdXRlIHRoZSByYXRlIGZvciBgdGFibGUyYCwgYW5kIGB0YWJsZTRhYCArIGB0YWJsZTRiYC4gWW91IHdpbGwgbmVlZCB0byBwZXJmb3JtIGZvdXIgb3BlcmF0aW9uczoKCiAgMS4gRXh0cmFjdCB0aGUgbnVtYmVyIG9mIFRCIGNhc2VzIHBlciBjb3VudHJ5IHBlciB5ZWFyLgogIDIuIEV4dHJhY3QgdGhlIG1hdGNoaW5nIHBvcHVsYXRpb24gcGVyIGNvdW50cnkgcGVyIHllYXIuCiAgMy4gRGl2aWRlIGNhc2VzIGJ5IHBvcHVsYXRpb24sIGFuZCBtdWx0aXBseSBieSAxMDAwMC4KICA0LiBTdG9yZSBiYWNrIGluIHRoZSBhcHByb3ByaWF0ZSBwbGFjZS4KCmBgYHtyfQp0MmNhc2VzIDwtIHRhYmxlMiAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY2FzZXMiKSAlPiUKICBzZWxlY3QoY291bnRyeSwgeWVhciwgY2FzZXMgPSBjb3VudCkKdDJwb3AgPC0gdGFibGUyICU+JQogIGZpbHRlcih0eXBlID09ICJwb3B1bGF0aW9uIikgJT4lCiAgc2VsZWN0KGNvdW50cnksIHllYXIsIHBvcCA9IGNvdW50KQp0MnJhdGUgPC0gdDJjYXNlcyAlPiUKICBsZWZ0X2pvaW4odDJwb3AsIGJ5ID0gYygiY291bnRyeSIsICJ5ZWFyIikpICU+JQogIG11dGF0ZShyYXRlID0gKGNhc2VzIC8gcG9wKSAqIDEwMDAwKQp0MnJhdGUKYGBgCgpgYGB7cn0KdDRyYXRlIDwtIHRhYmxlNGEgJT4lCiAgbGVmdF9qb2luKHRhYmxlNGIsIGJ5ID0gYygiY291bnRyeSIpLCBzdWZmaXggPSBjKCJjYXNlcyIsICJwb3AiKSkgJT4lCiAgbXV0YXRlKAogICAgYDE5OTlyYXRlYCA9IChgMTk5OWNhc2VzYCAvIGAxOTk5cG9wYCkgKiAxMDAwMCwKICAgIGAyMDAwcmF0ZWAgPSAoYDIwMDBjYXNlc2AgLyBgMjAwMHBvcGApICogMTAwMDAKICApCnQ0cmF0ZQpgYGAKCldoaWNoIHJlcHJlc2VudGF0aW9uIGlzIGVhc2llc3QgdG8gd29yayB3aXRoPyBXaGljaCBpcyBoYXJkZXN0PyBXaHk/CgoqKmB0YWJsZTNgIHdvdWxkIGJlIHdvcnN0IG9mIGFsbCBiZWNhdXNlIGl0IHJlcXVpcmVzIHRleHQgcHJvY2Vzc2luZy4gYHRhYmxlMmAgcmVxdWlyZWQgc29tZSBpbnRlcm1lZGlhdGUgc3RlcHMgYmVmb3JlIHB1dHRpbmcgdGhpbmdzIGJhY2sgdG9nZXRoZXIgYnV0IHJlc3VsdHMgaW4gYSBnZW5lcmFsbHkgdGlkeSBmb3JtYXQuIGB0YWJsZTRhYCBhbmQgYHRhYmxlNGJgIHJlcXVpcmVkIHNvbWUgZXh0cmEgYXJndW1lbnRzIHRvIHRoZSBqb2luIGZ1bmN0aW9uIGZvciBjbGFyaXR5IGFuZCBlbmRzIHVwIHB1dHRpbmcgdGhlIGNhbGN1bGF0ZWQgcmF0ZXMgaW50byB0d28gc2VwYXJhdGUgY29sdW1ucyBzbyBpdCByZW1haW5zIHVudGlkeS4qKgoKMy4gUmVjcmVhdGUgdGhlIHBsb3Qgc2hvd2luZyBjaGFuZ2UgaW4gY2FzZXMgb3ZlciB0aW1lIHVzaW5nIGB0YWJsZTJgIGluc3RlYWQgb2YgYHRhYmxlMWAuIFdoYXQgZG8geW91IG5lZWQgdG8gZG8gZmlyc3Q/CgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQp0YWJsZTIgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNhc2VzIikgJT4lCiAgZ2dwbG90KGFlcyh5ZWFyLCBjb3VudCkpICsKICAgIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHJ5KSwgY29sb3VyID0gImdyZXk1MCIpICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGNvdW50cnkpKSArCiAgICB5bGFiKCJjYXNlcyIpCmBgYAoKKipJIG5lZWRlZCB0byBmaWx0ZXIgdGhlIGRhdGEgdG8gc2VsZWN0IG9ubHkgdGhlIHJvd3MgdGhhdCBoYWQgbnVtYmVycyBvZiBjYXNlcywgYW5kIHRoZW4gSSBhbHNvIGNoYW5nZWQgdGhlIGxhYmVsIG9uIHRoZSB5LWF4aXMgdG8gY29ycmVjdGx5IGRlc2NyaWJlIHRoZSB2YXJpYWJsZS4qKgoKIyAxMi4zIFNwcmVhZGluZyBhbmQgZ2F0aGVyaW5nCgojIyAxMi4zLjMgRXhlcmNpc2VzCgoxLiBXaHkgYXJlIGBnYXRoZXIoKWAgYW5kIGBzcHJlYWQoKWAgbm90IHBlcmZlY3RseSBzeW1tZXRyaWNhbD8KCkNhcmVmdWxseSBjb25zaWRlciB0aGUgZm9sbG93aW5nIGV4YW1wbGU6CgpgYGB7cn0Kc3RvY2tzIDwtIHRpYmJsZSgKICB5ZWFyICAgPSBjKDIwMTUsIDIwMTUsIDIwMTYsIDIwMTYpLAogIGhhbGYgID0gYyggICAxLCAgICAyLCAgICAgMSwgICAgMiksCiAgcmV0dXJuID0gYygxLjg4LCAwLjU5LCAwLjkyLCAwLjE3KQopCnN0b2NrcyAlPiUgCiAgc3ByZWFkKHllYXIsIHJldHVybikgICU+JSAKICBnYXRoZXIoInllYXIiLCAicmV0dXJuIiwgYDIwMTVgOmAyMDE2YCkKYGBgCgooSGludDogbG9vayBhdCB0aGUgdmFyaWFibGUgdHlwZXMgYW5kIHRoaW5rIGFib3V0IGNvbHVtbiBuYW1lcy4pCgoqKmBzcHJlYWQoKWAgb25seSBuZWVkcyB0d28gYXJndW1lbnRzIGJlY2F1c2UgaXQgZGV0ZXJtaW5lcyB0aGUgbmV3IGNvbHVtbiBuYW1lcyBmcm9tIHRoZSB2YWx1ZXMgaW4gdGhlIGBrZXlgIGNvbHVtbi4gQWxsIGl0IG5lZWRzIHRvIGRvIGlzIGNvZXJjZSB0aG9zZSB2YWx1ZXMgdG8gYmUgc3RyaW5ncyBzbyB0aGV5IGNhbiBmdW5jdGlvbiBhcyB2YXJpYWJsZSBuYW1lcy4gYGdhdGhlcigpYCBuZWVkcyB0byBiZSB0b2xkIHRoZSBuZXcgY29sdW1uIG5hbWVzIGFuZCB0aGVuIHdoaWNoIGV4aXN0aW5nIHZhcmlhYmxlcyBhcmUgdG8gYmUgY29udmVydGVkIGludG8gdGhvc2Uga2V5LXZhbHVlIGNvbHVtbnMuKioKCkJvdGggYHNwcmVhZCgpYCBhbmQgYGdhdGhlcigpYCBoYXZlIGEgY29udmVydCBhcmd1bWVudC4gV2hhdCBkb2VzIGl0IGRvPwoKKipJZiBgY29udmVydCA9IFRSVUVgIGlzIHBhc3NlZCB0byBlaXRoZXIgZnVuY3Rpb24gdGhlbiBpdCB3aWxsIGF0dGVtcHQgdG8gY29udmVydCB0aGUgbmV3IHZhcmlhYmxlcyB0byBhbiBhcHByb3ByaWF0ZSB0eXBlLiBOb3RlIHRoYXQgYHllYXJgIGluIHRoZSBleGFtcGxlIGNvZGUgYWJvdmUgaGFzIGVuZGVkIHVwIGFzIGEgc3RyaW5nLCBiZWNhdXNlIHRoZSBgZ2F0aGVyKClgIGZ1bmN0aW9uIGhhZCB1c2VkIHRoZSBgMjAxNWAgYW5kIGAyMDE2YCB2YXJpYWJsZSBuYW1lcyBhcyBzdHJpbmdzLiBSdW5uaW5nIHRoZSBzYW1lIGNvZGUgd2l0aCBjb252ZXJzaW9uIHdpbGwgc2VlIGl0IHJldHVybiB0byBiZWluZyBhIG51bWVyaWMgdmFyaWFibGUsIGFzICBzaG93biBiZWxvdy4qKgoKYGBge3J9CnN0b2NrcyA8LSB0aWJibGUoCiAgeWVhciAgID0gYygyMDE1LCAyMDE1LCAyMDE2LCAyMDE2KSwKICBoYWxmICA9IGMoICAgMSwgICAgMiwgICAgIDEsICAgIDIpLAogIHJldHVybiA9IGMoMS44OCwgMC41OSwgMC45MiwgMC4xNykKKQpzdG9ja3MgJT4lIAogIHNwcmVhZCh5ZWFyLCByZXR1cm4pICAlPiUgCiAgZ2F0aGVyKCJ5ZWFyIiwgInJldHVybiIsIGAyMDE1YDpgMjAxNmAsIGNvbnZlcnQgPSBUUlVFKQpgYGAKCjIuIFdoeSBkb2VzIHRoaXMgY29kZSBmYWlsPwoKYGBge3J9CnRhYmxlNGEgJT4lIAogIGdhdGhlcigxOTk5LCAyMDAwLCBrZXkgPSAieWVhciIsIHZhbHVlID0gImNhc2VzIikKYGBgCgoqKlRoZSBleGlzdGluZyB2YXJpYWJsZSBuYW1lcyBhcmUgbm9uLXN5bnRhY3RpYyBzbyB0aGUgYXJndW1lbnRzIG5lZWQgdG8gYmUgc3Vycm91bmRlZCBieSBiYWNrdGlja3MgLSBzZWUgYmVsb3cuKioKCmBgYHtyfQp0YWJsZTRhICU+JSAKICBnYXRoZXIoYDE5OTlgLCBgMjAwMGAsIGtleSA9ICJ5ZWFyIiwgdmFsdWUgPSAiY2FzZXMiKQpgYGAKCjMuIFdoeSBkb2VzIHNwcmVhZGluZyB0aGlzIHRpYmJsZSBmYWlsPyBIb3cgY291bGQgeW91IGFkZCBhIG5ldyBjb2x1bW4gdG8gZml4IHRoZSBwcm9ibGVtPwoKYGBge3J9CnBlb3BsZSA8LSB0cmliYmxlKAogIH5uYW1lLCAgICAgICAgICAgICB+a2V5LCAgICB+dmFsdWUsCiAgIy0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tfC0tLS0tLQogICJQaGlsbGlwIFdvb2RzIiwgICAiYWdlIiwgICAgICAgNDUsCiAgIlBoaWxsaXAgV29vZHMiLCAgICJoZWlnaHQiLCAgIDE4NiwKICAiUGhpbGxpcCBXb29kcyIsICAgImFnZSIsICAgICAgIDUwLAogICJKZXNzaWNhIENvcmRlcm8iLCAiYWdlIiwgICAgICAgMzcsCiAgIkplc3NpY2EgQ29yZGVybyIsICJoZWlnaHQiLCAgIDE1NgopCnBlb3BsZSAlPiUKICBzcHJlYWQoa2V5LCB2YWx1ZSkKYGBgCgoqKlRoZSB0aGlyZCByb3cgaW4gdGhlIG9yaWdpbmFsIGRhdGFzZXQgaGFzIHRoZSBzYW1lIG5hbWUgYW5kIGtleSBhcyB0aGUgZmlyc3Qgcm93LCBpLmUuLCB0aGUgZnVuY3Rpb24gcnVucyBpbnRvIGEgc2l0dWF0aW9uIHdoZXJlIHRoZXJlIGFyZSB0d28gcG9zc2libGUgdmFsdWVzIHRvIGdvIGludG8gdGhlIG9uZSBjZWxsIGZvciBQaGlsbGlwIFdvb2RzJ3MgYWdlIGNvbHVtbi4gWW91IGNvdWxkIGFkZCBhIGNvbHVtbiB0aGF0IGFsbG93cyB0aGUgdGlkeWluZyBmdW5jdGlvbiB0byB1bmlxdWVseSBpZGVudGlmeSBwZW9wbGUgd2hvIG1pZ2h0IGhhdmUgdGhlIHNhbWUgbmFtZSwgZS5nLiwgYWRkIGFuIGFkZHJlc3Mgb3IgYSB1bmlxdWUgSUQgbnVtYmVyLioqCgo0LiBUaWR5IHRoZSBzaW1wbGUgdGliYmxlIGJlbG93LiBEbyB5b3UgbmVlZCB0byBzcHJlYWQgb3IgZ2F0aGVyIGl0PyBXaGF0IGFyZSB0aGUgdmFyaWFibGVzPwoKYGBge3J9CnByZWcgPC0gdHJpYmJsZSgKICB+cHJlZ25hbnQsIH5tYWxlLCB+ZmVtYWxlLAogICJ5ZXMiLCAgICAgTkEsICAgIDEwLAogICJubyIsICAgICAgMjAsICAgIDEyCikKcHJlZyAlPiUKICBnYXRoZXIoInNleCIsICJuIiwgYG1hbGVgOmBmZW1hbGVgKQpgYGAKCiMgMTIuNCBTZXBhcmF0aW5nIGFuZCB1bml0aW5nCgojIyAxMi40LjMgRXhlcmNpc2VzCgoxLiBXaGF0IGRvIHRoZSBgZXh0cmFgIGFuZCBgZmlsbGAgYXJndW1lbnRzIGRvIGluIGBzZXBhcmF0ZSgpYD8gRXhwZXJpbWVudCB3aXRoIHRoZSB2YXJpb3VzIG9wdGlvbnMgZm9yIHRoZSBmb2xsb3dpbmcgdHdvIHRveSBkYXRhc2V0cy4KCmBgYHtyfQo/c2VwYXJhdGUKYGBgCgoqKlRoZXNlIHR3byBhcmd1bWVudHMgYWxsb3cgdXMgdG8gc3BlY2lmeSB3aGF0IGhhcHBlbnMgd2l0aCBhbnkgcm93KHMpIHRoYXQgaGFzIHRvbyBtYW55IChgZXh0cmFgKSBvciB0b28gZmV3IChgZmlsbGApIHBpZWNlcyB0byBmaXQgdGhlIGBpbnRvYCB2YXJpYWJsZXMuIEJ5IGRlZmF1bHQsIHdhcm5pbmdzIHdpbGwgYmUgaXNzdWVkIGluIGJvdGggY2FzZXMsIGJ1dCB3ZSBjYW4gaW5zdGVhZCBgZHJvcGAgZXh0cmEgdmFsdWVzIG9yIGBtZXJnZWAgdGhlbSBpbnRvIHRoZSBmaW5hbCBjb2x1bW4sIGFuZCB3ZSBjYW4gc3BlY2lmeSB3aGV0aGVyIG1pc3NpbmcgdmFsdWVzIHNob3VsZCBiZSBmaWxsZWQgb24gdGhlIHJpZ2h0IChmaW5hbCBjb2x1bW4ocykpIG9yIGxlZnQuKioKCmBgYHtyfQp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSxmLGciLCAiaCxpLGoiKSkgJT4lIAogIHNlcGFyYXRlKHgsIGMoIm9uZSIsICJ0d28iLCAidGhyZWUiKSkKdGliYmxlKHggPSBjKCJhLGIsYyIsICJkLGUsZixnIiwgImgsaSxqIikpICU+JSAKICBzZXBhcmF0ZSh4LCBjKCJvbmUiLCAidHdvIiwgInRocmVlIiksIGV4dHJhID0gImRyb3AiKQp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSxmLGciLCAiaCxpLGoiKSkgJT4lIAogIHNlcGFyYXRlKHgsIGMoIm9uZSIsICJ0d28iLCAidGhyZWUiKSwgZXh0cmEgPSAibWVyZ2UiKQpgYGAKCmBgYHtyfQp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSIsICJmLGcsaSIpKSAlPiUgCiAgc2VwYXJhdGUoeCwgYygib25lIiwgInR3byIsICJ0aHJlZSIpKQp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSIsICJmLGcsaSIpKSAlPiUgCiAgc2VwYXJhdGUoeCwgYygib25lIiwgInR3byIsICJ0aHJlZSIpLCBmaWxsID0gInJpZ2h0IikKdGliYmxlKHggPSBjKCJhLGIsYyIsICJkLGUiLCAiZixnLGkiKSkgJT4lIAogIHNlcGFyYXRlKHgsIGMoIm9uZSIsICJ0d28iLCAidGhyZWUiKSwgZmlsbCA9ICJsZWZ0IikKYGBgCgoyLiBCb3RoIGB1bml0ZSgpYCBhbmQgYHNlcGFyYXRlKClgIGhhdmUgYSBgcmVtb3ZlYCBhcmd1bWVudC4gV2hhdCBkb2VzIGl0IGRvPyBXaHkgd291bGQgeW91IHNldCBpdCB0byBgRkFMU0VgPwoKKipJdCByZW1vdmVzIHRoZSBpbnB1dCBjb2x1bW4ocykgYWZ0ZXIgeW91J3ZlIHNlcGFyYXRlZCBvciB1bml0ZWQgeW91ciBkYXRhLiBUaGUgZGVmYXVsdCBpcyBgVFJVRWAgYnV0IHlvdSB3b3VsZCBzZXQgaXQgdG8gYEZBTFNFYCBpZiB5b3Ugd2FudGVkIHRvIHJldGFpbiB0aGUgb3JpZ2luYWwgZGF0YSBmb3IgYW55IHJlYXNvbiwgd2hldGhlciB0aGF0IGlzIGluIGNhc2UgeW91IG1pZ2h0IG5lZWQgdG8gcmUtcnVuIHRoZSBmdW5jdGlvbiB3aXRoIGFkanVzdG1lbnRzIG9yIGlmIHRoZSBvcmlnaW5hbCBkYXRhIGZvcm1hdCBpcyBhbHNvIHVzZWZ1bCBmb3IgYW5hbHlzaXMgaW4gc29tZSB3YXkuKioKCjMuIENvbXBhcmUgYW5kIGNvbnRyYXN0IGBzZXBhcmF0ZSgpYCBhbmQgYGV4dHJhY3QoKWAuIFdoeSBhcmUgdGhlcmUgdGhyZWUgdmFyaWF0aW9ucyBvZiBzZXBhcmF0aW9uIChieSBwb3NpdGlvbiwgYnkgc2VwYXJhdG9yLCBhbmQgd2l0aCBncm91cHMpLCBidXQgb25seSBvbmUgYHVuaXRlYD8KCmBgYHtyfQo/dGlkeXI6OmV4dHJhY3QKYGBgCgoqKmBleHRyYWN0KClgIGxldHMgeW91IHNwZWNpZnkgcmVndWxhciBleHByZXNzaW9ucyB3aXRoIGNhcHR1cmluZyBncm91cHMgYW5kIHdvdWxkIHN1cHBvcnQgbW9yZSBjb21wbGV4IHJlZ3VsYXIgZXhwcmVzc2lvbnMgdG8gcHJvY2VzcyB0aGUgdmFsdWVzIC0gaWYgdGhlIGdyb3VwcyBkb24ndCBtYXRjaCB0aGVuIHRoZSBkYXRhIHdpbGwgY29tZSBvdXQgYXMgYE5BYC4gYHNlcGFyYXRlKClgIGlzIHRoZSBtb3JlIHNpbXBsZSBhcHByb2FjaCB0aGF0IGxpa2VseSB3b3JrcyBmb3IgbW9zdCBjaXJjdW1zdGFuY2VzIHdoZXJlIHlvdSBqdXN0IG5lZWQgdG8gc3BlY2lmeSBhIHNlcGFyYXRvciwgYW5kIGl0IGFsc28gc2VwYXJhdGVzIGJ5IHBvc2l0aW9uLiBUaGVyZSBhcmUgdGhyZWUgYXBwcm9hY2hlcyB0byBzZXBhcmF0aW9uIGJ1dCBvbmx5IG9uZSBmb3IgdW5pdGluZyBiZWNhdXNlIGRhdGEgdGhhdCByZXF1aXJlcyBzZXBhcmF0aW9uIGNhbiBjb21lIGluIGFueSB2YXJpZXR5IG9mIGZvcm1zIGFuZCB5b3UgbmVlZCBhIG1ldGhvZCB0aGF0IHdvcmtzIGZvciB0aGUgc3BlY2lmaWMgZm9ybSB5b3VyIGRhdGEgY29tZXMgaW4gLSBpdCBtaWdodCBoYXZlIGEgc2VwYXJhdG9yLCBpdCBtaWdodCBub3QgaGF2ZSBzZXBhcmF0b3JzIGJ1dCBoYXZlIGZpeGVkIHBvc2l0aW9uaW5nLCBldGMuIE9uIHRoZSBvdGhlciBoYW5kLCBqb2luaW5nIHZhbHVlcyB0b2dldGhlciBjYW4gYmUgZGVhbHQgd2l0aCBpbiBhIHNpbmdsZSBtZXRob2QgdGhhdCBwcm92aWRlcyB0aGUgbmVjZXNzYXJ5IHBhcmFtZXRlcnMgKGUuZy4sIHNlcGFyYXRvciwgd2hpY2ggY2FuIGFsc28gYmUgc2V0IHRvIGFuIGVtcHR5IHN0cmluZykuKioKCiMgMTIuNSBNaXNzaW5nIHZhbHVlcwoKIyMgMTIuNS4xIEV4ZXJjaXNlcwoKMS4gQ29tcGFyZSBhbmQgY29udHJhc3QgdGhlIGBmaWxsYCBhcmd1bWVudHMgdG8gYHNwcmVhZCgpYCBhbmQgYGNvbXBsZXRlKClgLgoKYGBge3J9Cj9zcHJlYWQKP2NvbXBsZXRlCmBgYAoKKipUaGUgYGZpbGxgIGFyZ3VtZW50IGluIGBzcHJlYWQoKWAgc3BlY2lmaWVzIHdoYXQgYW55IG1pc3NpbmcgdmFsdWVzIC0gYm90aCBleHBsaWNpdCBhbmQgaW1wbGljaXQgLSB3aWxsIGJlIHNldCB0byBpbiB0aGUgbmV3IGNvbHVtbnMuIEJ5IGRlZmF1bHQgaXQgd2lsbCBiZSBgTkFgIGJ1dCBjYW4gYmUgc2V0IHRvIGFueSBvdGhlciB2YWx1ZS4gSW4gYGNvbXBsZXRlKClgLCB0aGUgYGZpbGxgIGFyZ3VtZW50IHByb3ZpZGVzIGEgbmFtZWQgbGlzdCB0aGF0IGlkZW50aWZpZXMgZm9yIGVhY2ggdmFyaWFibGUgd2hhdHZhbHVlIHNob3VsZCBiZSB1c2VkIHdoZW4gYW4gaW1wbGljaXQgbWlzc2luZyB2YWx1ZSBpcyBjb252ZXJ0ZWQgdG8gZXhwbGljaXQgbWlzc2luZy4gVGhlIHNhbWUgdmFsdWUgd2lsbCBhbHNvIHJlcGxhY2UgZXhpc3RpbmcgZXhwbGljaXQgbWlzc2luZyB2YWx1ZXMuIEJvdGggYXBwcm9hY2hlcyBhcHBlYXIgdG8gZW5zdXJlIHRoYXQgaW1wbGljaXQgbWlzc2luZyB2YWx1ZXMgYmVjb21lIGV4cGxpY2l0LCBhbmQgdGhleSBwcm92aWRlIHRoZSBwb3NzaWJpbGl0eSBvZiB1c2luZyBhbiBhbHRlcm5hdGl2ZSB2YWx1ZSBpbnN0ZWFkIG9mIGBOQWAuKioKCjIuIFdoYXQgZG9lcyB0aGUgZGlyZWN0aW9uIGFyZ3VtZW50IHRvIGBmaWxsKClgIGRvPwoKKipCeSBkZWZhdWx0IGl0IHNwZWNpZmllcyB0aGF0IHRoZSBmaWxsIHNob3VsZCBiZSBgZG93bmAsIGllIHRoZSBtaXNzaW5nIHZhbHVlIHNob3VsZCBiZSBmaWxsZWQgYnkgdGhlIG5lYXJlc3QgdmFsdWUgYWJvdmUgaXQsIGJ1dCBpdCBjYW4gYWxzbyBzcGVjaWZ5IGB1cGAgaW5zdGVhZC4qKgoKIyAxMi42IENhc2UgU3R1ZHkKCiMjIDEyLjYuMSBFeGVyY2lzZXMKCjEuIEluIHRoaXMgY2FzZSBzdHVkeSBJIHNldCBgbmEucm0gPSBUUlVFYCBqdXN0IHRvIG1ha2UgaXQgZWFzaWVyIHRvIGNoZWNrIHRoYXQgd2UgaGFkIHRoZSBjb3JyZWN0IHZhbHVlcy4gSXMgdGhpcyByZWFzb25hYmxlPyBUaGluayBhYm91dCBob3cgbWlzc2luZyB2YWx1ZXMgYXJlIHJlcHJlc2VudGVkIGluIHRoaXMgZGF0YXNldC4gQXJlIHRoZXJlIGltcGxpY2l0IG1pc3NpbmcgdmFsdWVzPyBXaGF04oCZcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGFuIGBOQWAgYW5kIHplcm8/CgpgYGB7cn0Kd2hvICU+JQogIGdhdGhlcihjb2RlLCB2YWx1ZSwgbmV3X3NwX20wMTQ6bmV3cmVsX2Y2NSkgJT4lIAogIG11dGF0ZShjb2RlID0gc3RyaW5ncjo6c3RyX3JlcGxhY2UoY29kZSwgIm5ld3JlbCIsICJuZXdfcmVsIikpICU+JQogIHNlcGFyYXRlKGNvZGUsIGMoIm5ldyIsICJ0eXBlIiwgInNleGFnZSIpKSAlPiUgCiAgc2VsZWN0KC1uZXcsIC1pc28yLCAtaXNvMykgJT4lIAogIHNlcGFyYXRlKHNleGFnZSwgYygic2V4IiwgImFnZSIpLCBzZXAgPSAxKQpgYGAKCmBgYHtyfQp3aG8gJT4lCiAgZ2F0aGVyKGNvZGUsIHZhbHVlLCBuZXdfc3BfbTAxNDpuZXdyZWxfZjY1KSAlPiUgCiAgbXV0YXRlKGNvZGUgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShjb2RlLCAibmV3cmVsIiwgIm5ld19yZWwiKSkgJT4lCiAgc2VwYXJhdGUoY29kZSwgYygibmV3IiwgInR5cGUiLCAic2V4YWdlIikpICU+JSAKICBzZWxlY3QoLW5ldywgLWlzbzIsIC1pc28zKSAlPiUgCiAgc2VwYXJhdGUoc2V4YWdlLCBjKCJzZXgiLCAiYWdlIiksIHNlcCA9IDEpICU+JQogIGNvbXBsZXRlKGNvdW50cnksIHllYXIsIHR5cGUsIHNleCwgYWdlKQpgYGAKCioqVGhlIGFkZGl0aW9uIG9mIG1vcmUgdGhhbiAxMCwwMDAgcm93cyB1c2luZyBgY29tcGxldGUoKWAgb24gdGhlIHRpZHkgZGF0YXNldCBzdWdnZXN0cyB0aGF0IHRoZXJlIHdlcmUgaW1wbGljaXQgbWlzc2luZyB2YWx1ZXMuIEFuIGBOQWAgdmFsdWUgaW5kaWNhdGVzIHRoYXQgd2UgZG9uJ3Qga25vdyBob3cgbWFueSBjYXNlcyB0aGVyZSB3ZXJlIHdpdGhpbiB0aGUgZ2l2ZW4gY29tYmluYXRpb24gb2YgY291bnRyeSwgeWVhciwgdHlwZSwgc2V4IGFuZCBhZ2UsIHdoZXJlYXMgYSB6ZXJvIGluZGljYXRlcyB0aGF0IHRoZXJlIHdlcmUgbm8gb2JzZXJ2ZWQgY2FzZXMuIEFsdGhvdWdoIGl0IGNhbiBiZSBjb252ZW5pZW50IGFuZCBoZWxwZnVsIHdoZW4gcHJvZHVjaW5nIHRoZSBkYXRhIHByb2Nlc3NpbmcgY29tbWFuZHMgdG8gc3RyaXAgb3V0IHRoZSBtaXNzaW5nIHZhbHVlcywgYW5hbHlzaXMgb2YgdGhlIG1pc3NpbmcgZGF0YSBjYW4gaXRzZWxmIGJlIGluZm9ybWF0aXZlLCBlLmcuLCB3ZXJlIHJlY29yZHMgaW4gc29tZSBjb3VudHJpZXMgbW9yZSBsaWtlbHkgdG8gYmUgaW5jb21wbGV0ZT8qKgoKMi4gV2hhdCBoYXBwZW5zIGlmIHlvdSBuZWdsZWN0IHRoZSBgbXV0YXRlKClgIHN0ZXA/IGAobXV0YXRlKGtleSA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKGtleSwgIm5ld3JlbCIsICJuZXdfcmVsIikpKWAKCmBgYHtyfQp3aG8gJT4lCiAgZ2F0aGVyKGNvZGUsIHZhbHVlLCBuZXdfc3BfbTAxNDpuZXdyZWxfZjY1KSAlPiUgCiAgIyBtdXRhdGUoY29kZSA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKGNvZGUsICJuZXdyZWwiLCAibmV3X3JlbCIpKSAlPiUKICBzZXBhcmF0ZShjb2RlLCBjKCJuZXciLCAidHlwZSIsICJzZXhhZ2UiKSkgJT4lIAogIHNlbGVjdCgtbmV3LCAtaXNvMiwgLWlzbzMpICU+JSAKICBzZXBhcmF0ZShzZXhhZ2UsIGMoInNleCIsICJhZ2UiKSwgc2VwID0gMSkKYGBgCgoqKlRoZSByb3dzIHRoYXQgaGF2ZSBhIG1pc3NpbmcgdW5kZXJzY29yZSBpbiB0aGUga2V5IGNvbHVtbiAodmFsdWVzIGJlZ2lubmluZyB3aXRoIGBuZXdyZWxgIHJhdGhlciB0aGFuIGBuZXdfcmVsYCkgd29uJ3Qgc2VwYXJhdGUgcHJvcGVybHkgYXMgdGhleSB3aWxsIHB1dCBgbmV3cmVsYCBpbnRvIHRoZSBgIm5ldyJgIHZhcmlhYmxlLCB0aGUgdmFsdWUgdGhhdCBzaG91bGQgYmUgYHNleGFnZWAgaW50byB0aGUgYHR5cGVgIGNvbHVtbiBhbmQgd2lsbCBoYXZlIG5vdGhpbmcgbGVmdCB0byBnbyBpbnRvIHRoZSBgc2V4YWdlYCBjb2x1bW4uKioKCjMuIEkgY2xhaW1lZCB0aGF0IGBpc28yYCBhbmQgYGlzbzNgIHdlcmUgcmVkdW5kYW50IHdpdGggYGNvdW50cnlgLiBDb25maXJtIHRoaXMgY2xhaW0uCgpgYGB7cn0Kd2hvICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGlzbzIsIGlzbzMpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkKYGBgCgoqKkluc3BlY3Rpb24gb2YgdGhlIHN1bW1hcmlzZWQgZGF0YSBzaG93cyB0aGF0IGVhY2ggY291bnRyeSBoYXMgYSBzaW5nbGUgY29ycmVzcG9uZGluZyBgaXNvMmAgdmFsdWUgYW5kIGEgc2luZ2xlIGBpc28zYCB2YWx1ZS4qKgoKNC4gRm9yIGVhY2ggY291bnRyeSwgeWVhciwgYW5kIHNleCBjb21wdXRlIHRoZSB0b3RhbCBudW1iZXIgb2YgY2FzZXMgb2YgVEIuIE1ha2UgYW4gaW5mb3JtYXRpdmUgdmlzdWFsaXNhdGlvbiBvZiB0aGUgZGF0YS4KCioqQSB0aW1lLXNlcmllcyBsaW5lIHBsb3QgZm9yIGVhY2ggY291bnRyeSB3aXRoIHNlcGFyYXRlIGNvbG91cmVkIGxpbmVzIGZvciBtYWxlcyBhbmQgZmVtYWxlcyB3b3VsZCBiZSBpbmZvcm1hdGl2ZSBhYm91dCB0cmVuZHMgb3ZlciB0aW1lIGluIGVhY2ggY291bnRyeSBhcyB3ZWxsIGFzIGFueSBzZXggZGlmZmVyZW5jZXMuIFdpdGggbW9yZSB0aGFuIDIwMCBjb3VudHJpZXMgaW4gdGhlIGRhdGFzZXQgYSBzdGFuZGFyZCBzbWFsbCBtdWx0aXBsZXMgcGxvdCB1c2luZyBhIGZhY2V0IGZ1bmN0aW9uIHdvbid0IGJlIHJlYWRhYmxlLCBzbyB3ZSB1c2UgdGhlIGBnZ2ZvcmNlYCBwYWNrYWdlJ3MgcGFnaW5hdGVkIGZhY2V0IHBsb3R0aW5nIGNhcGFiaWxpdHkuIEJlY2F1c2UgdGhlcmUgaXMgc2lnbmlmaWNhbnQgdmFyaWF0aW9uIChvcmRlcnMgb2YgbWFnaXR1ZGUpIGJldHdlZW4gY291bnRyaWVzIGluIHRoZSBudW1iZXIgb2YgY2FzZXMgYSB1bmlmb3JtIHNjYWxlIGFjcm9zcyB0aGUgZmFjZXRzJyB5LWF4aXMgd291bGQgbWVhbiBlYWNoIGluZGl2aWR1YWwgc3VicGxvdCBpc24ndCBjbGVhcmx5IHZpc3VhbGlzZWQsIHNvIHRoZSBgc2NhbGVzID0gImZyZWVfeSJgIGFyZ3VtZW50IGlzIHVzZWQuIFRoZSBwYWdlcyBhcmUgZ2VuZXJhdGVkIHZpYSBhIGZvciBsb29wIC0gaXQgdGFrZXMgYSBjb25zaWRlcmFibGUgdGltZSB0byBydW4gYnV0IHByb2R1Y2VzIHBsb3RzIHRoYXQgYXJlIGdlbmVyYWxseSBjbGVhciBhbmQgaW5mb3JtYXRpdmUuKioKCmBgYHtyfQpsaWJyYXJ5KGdnZm9yY2UpCndobzIgPC0gd2hvICU+JQogIGdhdGhlcihjb2RlLCB2YWx1ZSwgbmV3X3NwX20wMTQ6bmV3cmVsX2Y2NSwgbmEucm0gPSBUUlVFKSAlPiUgCiAgbXV0YXRlKGNvZGUgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShjb2RlLCAibmV3cmVsIiwgIm5ld19yZWwiKSkgJT4lCiAgc2VwYXJhdGUoY29kZSwgYygibmV3IiwgInR5cGUiLCAic2V4YWdlIikpICU+JSAKICBzZWxlY3QoLW5ldywgLWlzbzIsIC1pc28zKSAlPiUgCiAgc2VwYXJhdGUoc2V4YWdlLCBjKCJzZXgiLCAiYWdlIiksIHNlcCA9IDEpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIHllYXIsIHNleCkgJT4lCiAgc3VtbWFyaXNlKGNhc2VzID0gc3VtKHZhbHVlKSkKcCA8LSB3aG8yICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBjYXNlcywgY29sb3VyID0gc2V4KSkgKwogICAgZ2VvbV9saW5lKCkgKwogICAgZmFjZXRfd3JhcF9wYWdpbmF0ZSgiY291bnRyeSIsIG5jb2wgPSAzLCBucm93ID0gMywgc2NhbGVzID0gImZyZWVfeSIsIHBhZ2UgPSAxKQpwYWdlcyA8LSBuX3BhZ2VzKHApCmZvcihpIGluIDE6cGFnZXMpIHsKICBwcmludCgKICAgIHdobzIgJT4lCiAgICAgIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBjYXNlcywgY29sb3VyID0gc2V4KSkgKwogICAgICAgIGdlb21fbGluZSgpICsKICAgICAgICBmYWNldF93cmFwX3BhZ2luYXRlKCJjb3VudHJ5IiwgbmNvbCA9IDMsIG5yb3cgPSAzLCBzY2FsZXMgPSAiZnJlZV95IiwgcGFnZSA9IGkpCiAgKQp9CmBgYAo=